/**
 * ImageUtil.java version 1.0 APR 18, 2011
 *
 * Copyright 2011 NHN Corp. All rights Reserved.
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.design.oop.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.view.Display;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.ImageView;

import com.design.oop.R;
import com.design.oop.WheatBeerApplication;

/**
 * 이미지 처리에 기능들 모음 클래스
 */
public class ImageUtil {
	/**
	 * 이미지 file과 inSampleSize 값을 넘기면 bitmap 전달
	 * 
	 * @param file :  이미지 file
	 * @param compressionSize : inSampleSize 값
	 * @return
	 */
	public static Bitmap readBitmapFromFS(File file, int compressionSize) {
		final BitmapFactory.Options option = new Options();

		option.inPurgeable = true;
		option.inSampleSize = compressionSize;
		Bitmap image = null;
		FileInputStream fs = null;
		try {
			if (file.exists()) {
				fs = new FileInputStream(file);
				image = BitmapFactory.decodeStream(fs, null, option);
			}
		} catch (Exception e) {
			return null;
		} finally {
			CommonUtil.closeQuietly(fs);
		}

		return image;
	}

	/**
	 * 이미지에 inSampleSize 값을 넘기면 bitmap 전달
	 * 
	 * @param file : 이미지 path
	 * @param compression : inSampleSize 값
	 * @return
	 */
	public static Bitmap readImage(String file, int compression) {
		Bitmap image = null;
		BitmapFactory.Options opts = new BitmapFactory.Options();

		opts.inPreferredConfig = Bitmap.Config.ARGB_8888; // 32bit로 읽음.
		opts.inPurgeable = true; // 약한 참조로 이미지를 로드하는 옵션이다.
		opts.inSampleSize = compression;

		final short maxTry = 3;
		short reTry = 0;
		while (reTry++ < maxTry) {
			try {
				image = BitmapFactory.decodeFile(file, opts);
				break;
			} catch (OutOfMemoryError err) {
				opts.inSampleSize *= 2;
				// 프리뷰 화면에서 메모리 부족으로 사진 안 나오는 부분 수정. 메모리 부족 에러 발생시 샘플 사이즈를 높여서 재시도. modified sung-chul.
				continue;
			}
		}

		return image;
	}

	/**
	 * 이미지에 inSampleSize 값을 넘기면 rotate 정보까지 확인해서 bitmap 전달
	 * 
	 * @param file : 이미지 path
	 * @param compression : inSampleSize 값
	 * @return
	 */
	public static Bitmap readImageWithExif(String file, int compression) {
		Bitmap orgImage = null;
		Bitmap image = null;
		orgImage = readImage(file, compression);

		try {
			ExifInterface exif = new ExifInterface(file);
			int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
			int exifDegree = ImageUtil.exifOrientationToDegrees(exifOrientation);

			image = ImageUtil.rotate(orgImage, exifDegree);

			if (image != null) {
				orgImage.recycle();
			} else {
				image = orgImage;
			}
		} catch (IOException e) {
			return null;
		}

		return image;
	}

	/**
	 * Reads the bitmap from the inputstream and creates the bitmap object
	 * 
	 * @param imageStream
	 *            Stream representing the image response
	 * @return Bitmap
	 */
	public static Bitmap readImage(InputStream imageStream) {
		Bitmap image = null;
		ByteArrayOutputStream output = null;
		ByteArrayInputStream bais = null;
		try {

			output = new ByteArrayOutputStream();
			byte[] buffer = new byte[4096];
			int n = 0;

			while (-1 != (n = imageStream.read(buffer))) {
				output.write(buffer, 0, n);
			}
			int len = (output != null) ? output.size() : 0;

			if (len > 0) {
				bais = new ByteArrayInputStream(output.toByteArray());
				image = BitmapFactory.decodeStream(bais);
			}
		} catch (Exception e) {
			return null;
		} catch (Error err) {

		} finally {
			CommonUtil.closeQuietly(output);
			CommonUtil.closeQuietly(bais);
		}

		return image;
	}

	/**
	 * Bitmap Data를 jpeg 파일로 저장한다.
	 * 
	 * @param filePath : 저장할 이미지 path
	 * @param data : 저장할 이미지 Bitmap data
	 * @param quality : 압축률
	 * @return
	 */
	public static boolean saveJpegDataToFile(String filePath, Bitmap data, int quality) {
		boolean result = false;

		if (data == null) {
			return false;
		}

		OutputStream outputStream = null;

		try {
			outputStream = new FileOutputStream(filePath);
			result = data.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
		} catch (Exception e) {
			return false;
		} finally {
			CommonUtil.closeQuietly(outputStream);
		}

		return result;
	}

	/**
	 *  Bitmap Data를 Png 파일로 저장한다.
	 * 
	 * @param filePath : 저장할 이미지 path
	 * @param data : 저장할 이미지 Bitmap data
	 * @param quality : 압축률
	 * @return
	 */
	public static boolean savePngDataToFile(String filePath, Bitmap data, int quality) {
		boolean result = false;

		if (data == null) {
			return false;
		}

		OutputStream outputStream = null;
		try {
			outputStream = new FileOutputStream(filePath);
			result = data.compress(Bitmap.CompressFormat.PNG, quality, outputStream); // modified by sung-chul. jpg->png
		} catch (Exception e) {
			return false;
		} finally {
			CommonUtil.closeQuietly(outputStream);
		}

		return result;
	}

	/**
	 * Jpeg 이미지로부터 썸네일 이미지를 추출.
	 * 
	 * @param filePath  이미지 path
	 * @return
	 */
	public static Bitmap getThumbnailInJpeg(String filePath) {
		Bitmap bmpThumb = null;
		Bitmap bmpOrg = null;

		try {
			ExifInterface exif = new ExifInterface(filePath);
			byte[] byteThumb = null;
			BitmapFactory.Options opt = new BitmapFactory.Options();

			int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
			int exifDegree = ImageUtil.exifOrientationToDegrees(exifOrientation);

			if (!exif.hasThumbnail()) {
				return readImage(filePath, 240, 240, Bitmap.Config.ARGB_8888); // modified by sung-chul.
			}
			//			else {
			//				Log.i(TAG, "TAG_DATETIME = " + exif.getAttribute(exif.TAG_DATETIME));
			//				Log.i(TAG, "TAG_FLASH = " + exif.getAttribute(exif.TAG_FLASH));
			//				Log.i(TAG, "TAG_FOCAL_LENGTH = " + exif.getAttribute(exif.TAG_FOCAL_LENGTH));
			//				Log.i(TAG, "TAG_GPS_DATESTAMP = " + exif.getAttribute(exif.TAG_GPS_DATESTAMP));
			//				Log.i(TAG, "TAG_GPS_LATITUDE = " + exif.getAttribute(exif.TAG_GPS_LATITUDE));
			//				Log.i(TAG, "TAG_GPS_LATITUDE_REF = " + exif.getAttribute(exif.TAG_GPS_LATITUDE_REF));
			//				Log.i(TAG, "TAG_GPS_LONGITUDE = " + exif.getAttribute(exif.TAG_GPS_LONGITUDE));
			//				Log.i(TAG, "TAG_GPS_LONGITUDE_REF = " + exif.getAttribute(exif.TAG_GPS_LONGITUDE_REF));
			//				Log.i(TAG, "TAG_GPS_PROCESSING_METHOD = " + exif.getAttribute(exif.TAG_GPS_PROCESSING_METHOD));
			//				Log.i(TAG, "TAG_GPS_TIMESTAMP = " + exif.getAttribute(exif.TAG_GPS_TIMESTAMP));
			//				Log.i(TAG, "TAG_IMAGE_LENGTH = " + exif.getAttribute(exif.TAG_IMAGE_LENGTH));
			//				Log.i(TAG, "TAG_IMAGE_WIDTH = " + exif.getAttribute(exif.TAG_IMAGE_WIDTH));
			//				Log.i(TAG, "TAG_MAKE = " + exif.getAttribute(exif.TAG_MAKE));
			//				Log.i(TAG, "TAG_MODEL = " + exif.getAttribute(exif.TAG_MODEL));
			//				Log.i(TAG, "TAG_ORIENTATION = " + exif.getAttribute(exif.TAG_ORIENTATION));
			//				Log.i(TAG, "TAG_WHITE_BALANCE = " + exif.getAttribute(exif.TAG_WHITE_BALANCE));
			//			}
			opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
			//			opt.inSampleSize = 2;

			byteThumb = exif.getThumbnail();

			bmpOrg = BitmapFactory.decodeByteArray(byteThumb, 0, byteThumb.length, opt);
			bmpThumb = ImageUtil.rotate(bmpOrg, exifDegree);

			if (bmpThumb != null) {
				bmpOrg.recycle();
			} else {
				bmpThumb = bmpOrg;
			}
		} catch (IOException e) {
			return null;
		}

		return bmpThumb;
	}

	/**
	 * filepath 파일이 갤러리 DB에 등록되어 있다면 
	 * filepath에 대한 썸네일 이미지를 갤러 DB로부터 얻어온다.
	 * 
	 * @param cr
	 * 		
	 * @param filepath
	 * 		이 파일에 대한 썸네일 이미지를 갤러리 DB로부터 가져온다.
	 * @return
	 * 		썸네일 이미지 존재시 Bitmap 이미지를 반환하며 그렇지 않을 경우 null을 반환한다.
	 */
	public static Bitmap getThumbnailFromGallery(ContentResolver cr, String filepath, int imageType) {
		String[] proj = {MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION};
		String selection = MediaStore.Images.Media.DATA + "=?";
		String[] selectionArgs = {filepath};

		Cursor cur = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, proj, selection, selectionArgs, null);

		if (cur == null) {
			return null;
		}

		if (cur.getCount() != 0) {
			Bitmap thumbImg;
			Bitmap rotateImg;

			cur.moveToFirst();

			int nId = cur.getInt(0);
			int orientation = cur.getInt(1);

			thumbImg = getThumbnailFromGallery(cr, nId, imageType);
			rotateImg = rotate(thumbImg, orientation);

			if (rotateImg != null) {
				thumbImg.recycle();
				thumbImg = null;
			} else {
				rotateImg = thumbImg;
			}

			return thumbImg;
		}
		cur.close();

		return null;
	}

	/**
	 * 갤러리에 등록된 이미지(id)에 대한 썸네일 이미지를 반환한다.
	 * 
	 * @param cr
	 * @param nId
	 * 		갤러리 db에 등록된 이미지에 대한 id값.
	 * @return
	 * 		썸네일 이미지 존재시 Bitmap 이미지를 반환하며 그렇지 않을 경우 null을 반환한다.
	 */
	private static Bitmap getThumbnailFromGallery(ContentResolver cr, int nId, int imageType) {
		BitmapFactory.Options opt = new BitmapFactory.Options();

		opt.inPurgeable = true;
		opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
		return MediaStore.Images.Thumbnails.getThumbnail(cr, nId, imageType, opt);
	}

	/**
	 * 갤러리로부터 비디오 썸네일 이미지 얻기.
	 * 
	 * @param cr
	 * @param filepath
	 * @return
	 */
	public static Bitmap getVideoThumbnailInGalleryDB(ContentResolver cr, String filepath, int kind) {
		//Bitmap bMap = ThumbnailUtils.createVideoThumbnail(filepath, MediaStore.Video.Thumbnails.MINI_KIND);
		Bitmap imgThumb = null;
		String selection = MediaStore.Images.Media.DATA + "=?";
		String[] selectionArgs = {filepath};

		Cursor cursor = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, selection, selectionArgs, null);
		if (cursor == null) {
			return null;
		}

		if (cursor.getCount() != 0) {
			cursor.moveToFirst();
			int nId = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));

			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inSampleSize = 1;
			options.inPurgeable = true;

			imgThumb = MediaStore.Video.Thumbnails.getThumbnail(cr, nId, kind, options);
		}

		cursor.close();
		return imgThumb;
	}

	/**
	 * EXIF정보를 회전각도로 변환하는 메서드
	 * 
	 * @param exifOrientation EXIF 회전각
	 * @return 실제 각도
	 */
	public static int exifOrientationToDegrees(int exifOrientation) {

		switch (exifOrientation) {
			case ExifInterface.ORIENTATION_NORMAL:
				return 0;

			case ExifInterface.ORIENTATION_ROTATE_90:
				return 90;

			case ExifInterface.ORIENTATION_ROTATE_180:
				return 180;

			case ExifInterface.ORIENTATION_ROTATE_270:
				return 270;

			case ExifInterface.ORIENTATION_UNDEFINED:
				return 0;

		}

		return 0;
	}

	/**
	 * 이미지를 회전시킵니다.
	 * 
	 * @param bitmap 비트맵 이미지
	 * @param degrees 회전 각도
	 * @return 회전된 이미지
	 */
	public static Bitmap rotate(Bitmap bitmap, int degrees) {
		Bitmap converted = null;

		if (degrees != 0 && bitmap != null) {
			Matrix matrix = new Matrix();
			matrix.setRotate(degrees, (float)bitmap.getWidth() / 2, (float)bitmap.getHeight() / 2);

			try {
				converted = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
			} catch (OutOfMemoryError ex) {
				// 메모리가 부족하여 회전을 시키지 못할 경우 그냥 원본을 반환합니다.
				return null;
			}
		}

		return converted;
	}

	/**
	 * 이미지 로드시 targetWidth, targetHeight를 기준으로 하여 
	 * 이미지를 샘플링하여 읽어온다.
	 * 
	 * @param imagePath	이미지 경로
	 * @param targetWidth		
	 * @param targetHeight	
	 * @return
	 */
	public static synchronized Bitmap loadImageWithSampling(String imagePath, int targetWidth, int targetHeight, Bitmap.Config bmConfig) {
		// Get the dimensions of the bitmap
		BitmapFactory.Options bmOptions = new BitmapFactory.Options();
		bmOptions = ImageUtil.getBitmapOptions(imagePath);

		int[] imageSize = getBitmapSize(imagePath);

		int photoWidth = imageSize[0];
		int photoHeight = imageSize[1];

		// Determine how much to scale down the image
		int scaleFactor = Math.min(photoWidth / targetWidth, photoHeight / targetHeight);

		// Decode the image file into a Bitmap sized to fill the View
		bmOptions.inPreferredConfig = bmConfig;
		bmOptions.inJustDecodeBounds = false;
		bmOptions.inSampleSize = scaleFactor;

		Bitmap orgImage;
		Bitmap image = null;

		try {
			// 앱간 연동 시 null이 넘어 올 때가 있음.
			orgImage = BitmapFactory.decodeFile(imagePath, bmOptions);

			int i = 0;
			final int nMaxLoop = 5;

			while (orgImage == null && i++ < nMaxLoop) {
				Thread.sleep(200);
				orgImage = BitmapFactory.decodeFile(imagePath, bmOptions);
			}

			ExifInterface exif = new ExifInterface(imagePath);
			int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
			int exifDegree = ImageUtil.exifOrientationToDegrees(exifOrientation);

			if (isRotated(exifOrientation)) {
				image = ImageUtil.rotate(orgImage, exifDegree);

				if (image != null) {
					orgImage.recycle();
				}
			} else {
				image = orgImage;
			}
		} catch (Exception e) {
			return null;
		} catch (OutOfMemoryError e) {
			return null;
		}

		return image;
	}

	/**
	 * 비디오 경로 가져오기
	 * 
	 * @param cr
	 * @param contentUri
	 * @return
	 */
	public static String getVideoRealPathFromURI(ContentResolver cr, Uri contentUri) {
		// can post image 
		String[] proj = {MediaStore.Video.Media.DATA};

		Cursor cursor = cr.query(contentUri, proj, // Which columns to return 
			null, // WHERE clause; which rows to return (all rows) 
			null, // WHERE clause selection arguments (none) 
			null); // Order-by clause (ascending by name) 

		int path = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
		cursor.moveToFirst();

		String tmp = cursor.getString(path);
		cursor.close();

		return tmp;
	}

	public static String getImageRealPathFromURI(ContentResolver cr, Uri contentUri) {
		// can post image 
		String[] proj = {MediaStore.Images.Media.DATA};

		Cursor cursor = cr.query(contentUri, proj, // Which columns to return 
			null, // WHERE clause; which rows to return (all rows) 
			null, // WHERE clause selection arguments (none) 
			null); // Order-by clause (ascending by name) 

		if (cursor == null) {
			return contentUri.getPath();
		} else {
			int path = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
			cursor.moveToFirst();
			String tmp = null;
			try {
				tmp = cursor.getString(path);
			} catch (Exception e) {
				cursor.close();
				return null;
			}
			cursor.close();
			return tmp;
		}
	}

	public static final Bitmap readImage(String fullpath, int targetWidth, int targetHeight, Bitmap.Config bmConfig) {
		Bitmap sampleImage = loadImageWithSampling(fullpath, targetWidth, targetHeight, bmConfig);

		if (sampleImage == null) {
			return null;
		}

		Bitmap resizeImage = resizeBitmap(sampleImage, targetWidth, targetHeight);

		sampleImage.recycle();
		sampleImage = null;

		return resizeImage;
	}

	/**
	 * 비트맵 사이즈를 지정된 가로 사이즈 비율로 줄여준다.
	 * @param orgImage
	 * @param width
	 * @return Bitmap
	 */
	public static final Bitmap resizeBitmap(Bitmap orgImage, int width) {
		int newWidth;
		int newHeight;
		float rate;

		rate = (((float)width) / orgImage.getWidth());

		newWidth = (int)(orgImage.getWidth() * rate);
		newHeight = (int)(orgImage.getHeight() * rate);

		return Bitmap.createScaledBitmap(orgImage, newWidth, newHeight, true);
	}

	/**
	 * 원본 크기의 비율을 유지하면서 이미지의 크기를 조절한다.
	 * 
	 * @param orgImage
	 * @param width
	 * @param height
	 * @return
	 */
	public static final Bitmap resizeBitmap(Bitmap orgImage, int width, int height) {
		int newWidth;
		int newHeight;
		float rate;

		if (orgImage.getWidth() > orgImage.getHeight()) {
			newWidth = (width > height) ? width : height;
			newHeight = (width > height) ? height : width;
		} else {
			newWidth = (width > height) ? height : width;
			newHeight = (width > height) ? width : height;
		}

		rate = Math.min((((float)newHeight) / orgImage.getHeight()), (((float)newWidth) / orgImage.getWidth()));

		newWidth = (int)(orgImage.getWidth() * rate);
		newHeight = (int)(orgImage.getHeight() * rate);

		if ((orgImage.getWidth() * orgImage.getHeight()) < (newWidth * newHeight)) {
			/**
			 * 원본 크기가 새로 Resize하려는 크기보다 작은 경우에는 
			 * 원본을 반환한다.
			 */
			return orgImage.copy(orgImage.getConfig(), false);
		}

		return Bitmap.createScaledBitmap(orgImage, newWidth, newHeight, true);
	}

	interface BitmapLoadStrategy {
		public Bitmap loadBitmap();
	}

	static final int UNCONSTRAINED = -1;

	/**
	 * 
	 * @param filePath
	 * @param maxNumOfPixels 지정한 픽셀 수 만큼의 비트맵을 만든다.
	 * @return
	 */
	public static Bitmap makeBitmap(String filePath, int maxNumOfPixels) {
		try {
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inJustDecodeBounds = true;
			BitmapFactory.decodeFile(filePath, options);
			if (options.mCancel || options.outWidth == -1 || options.outHeight == -1) {
				return null;
			}
			options.inSampleSize = computeSampleSize(options, UNCONSTRAINED, maxNumOfPixels);
			options.inJustDecodeBounds = false;

			options.inDither = false;
			options.inPreferredConfig = Bitmap.Config.ARGB_8888;
			return BitmapFactory.decodeFile(filePath, options);
		} catch (OutOfMemoryError ex) {
			return null;
		}
	}

	/**
	 * 
	 * @param options
	 * @param minSideLength
	 * @param maxNumOfPixels
	 * @return
	 */
	public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);

		int roundedSize;
		if (initialSize <= 8) {
			roundedSize = 1;
			while (roundedSize < initialSize) {
				roundedSize <<= 1;
			}
		} else {
			roundedSize = (initialSize + 7) / 8 * 8;
		}

		return roundedSize;
	}

	/**
	 * 
	 * @param options
	 * @param minSideLength
	 * @param maxNumOfPixels
	 * @return
	 */
	private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
		double width = options.outWidth;
		double height = options.outHeight;

		int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : (int)Math.ceil(Math.sqrt(width * height / maxNumOfPixels));
		int upperBound = (minSideLength == UNCONSTRAINED) ? 128 : (int)Math.min(Math.floor(width / minSideLength), Math.floor(height / minSideLength));

		if (upperBound < lowerBound) {
			// return the larger one when there is no overlapping zone.
			return lowerBound;
		}

		if ((maxNumOfPixels == UNCONSTRAINED) && (minSideLength == UNCONSTRAINED)) {
			return 1;
		} else if (minSideLength == UNCONSTRAINED) {
			return lowerBound;
		} else {
			return upperBound;
		}
	}

	/**
	 * 
	 * @param oriPath
	 * @param targetPath
	 * @return
	 */
	public static boolean move(String oriPath, String targetPath) {
		File oriFile = new File(oriPath);
		File targetFile = new File(targetPath);

		return oriFile.renameTo(targetFile);
	}

	/**
	 * 
	 * @param oriPath
	 * @param targetPath
	 * @return
	 */
	public static boolean copyImage(String oriPath, String targetPath) {
		InputStream in = null;
		OutputStream out = null;
		byte[] buf = new byte[1024];

		try {
			in = new FileInputStream(oriPath);
			out = new FileOutputStream(targetPath);

			int len;

			while ((len = in.read(buf)) > 0) {
				out.write(buf, 0, len);
			}

			return true;
		} catch (IOException e) {
		} finally {
			buf = null;
			CommonUtil.closeQuietly(in);
			CommonUtil.closeQuietly(out);
		}

		return false;
	}

	/**
	 * 이미지의 크기를 얻는다.
	 * 
	 * @param path
	 * @return
	 */
	public static Options getBitmapOptions(String path) {
		if (path == null || path.length() == 0 || !(new File(path)).exists()) {
			return null;
		}

		Options opts = new Options();
		// 크기만 얻으려면 아래 옵션을 true로 해야함 // by 한경훈
		opts.inJustDecodeBounds = true;

		// opts.outWidth, opts.outHeight에 이미지의 크기가 들어감
		BitmapFactory.decodeFile(path, opts);
		return opts;
	}

	public static Options getBitmapSize(Resources resource, int resourceId) {
		Options opts = new Options();
		opts.inJustDecodeBounds = true;

		// opts.outWidth, opts.outHeight에 이미지의 크기가 들어감
		BitmapFactory.decodeResource(resource, resourceId, opts);
		return opts;
	}

	/**
	 * 이미지 확대/축소를 위해 두 손가락으로 이미지를 조작할 때 손가락 사이의 길이를 구함
	 * 두 손가락 사이의 공간 결정 (모션이벤트)
	 * 
	 * @param event
	 * @return
	 */
	public static float spacing(MotionEvent event) {
		float xValue = event.getX(0) - event.getX(1);
		float yValue = event.getY(0) - event.getY(1);

		return FloatMath.sqrt(xValue * xValue + yValue * yValue);
	}

	//중간 포인트를 리턴
	public static void midPoint(PointF point, MotionEvent event) {
		float xValue = event.getX(0) + event.getX(1);
		float yValue = event.getY(0) + event.getY(1);
		point.set(xValue / 2, yValue / 2);
	}

	public static boolean isRotated(Uri imageUri) {
		String imagePath = ImageUtil.getImageRealPathFromURI(WheatBeerApplication.getContext().getContentResolver(), imageUri);

		try {
			ExifInterface exif = new ExifInterface(imagePath);
			int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
			return isRotated(exifOrientation);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return false;
	}

	public static boolean isRotated(int exifOrientation) {
		return exifOrientation == ExifInterface.ORIENTATION_ROTATE_90 || exifOrientation == ExifInterface.ORIENTATION_ROTATE_180 || exifOrientation == ExifInterface.ORIENTATION_ROTATE_270;
	}

	public static synchronized ResizedBitmap getImageWithMaxSizeSampling(Uri imageUri, int maxWidth, int maxHeight) {
		String imagePath = ImageUtil.getImageRealPathFromURI(WheatBeerApplication.getContext().getContentResolver(), imageUri);
		return getImageWithMaxSizeSampling(imagePath, maxWidth, maxHeight);
	}

	public static synchronized ResizedBitmap getImageWithMaxSizeSampling(String realImagePath, int maxWidth, int maxHeight) {
		int[] savedImageSize = getBitmapSize(realImagePath);

		int savedImageWidth = savedImageSize[0];
		int savedImageHeight = savedImageSize[1];

		float imageRatio = (float)savedImageWidth / savedImageHeight;
		float boundaryRatio = (float)maxWidth / maxHeight;

		int resizedBitmapWidth = 0;
		int resizedBitmapHeight = 0;

		// 영역보다 이미지가 작으면 걍 배치
		if (savedImageWidth <= maxWidth && savedImageHeight <= maxHeight) {
			resizedBitmapWidth = savedImageWidth;
			resizedBitmapHeight = savedImageHeight;

			// 이미지의 가로비율이 영역의 가로비율보다 넓을 경우.. 세로에 맞춘다.
		} else if (boundaryRatio > imageRatio) {
			resizedBitmapHeight = maxHeight;
			resizedBitmapWidth = maxHeight * savedImageWidth / savedImageHeight;
		} else {
			resizedBitmapWidth = maxWidth;
			resizedBitmapHeight = maxWidth * savedImageHeight / savedImageWidth;
		}

		if (resizedBitmapWidth == 0) {
			resizedBitmapWidth = 1;
		}

		if (resizedBitmapHeight == 0) {
			resizedBitmapHeight = 1;
		}

		ResizedBitmap resizedBitmap = new ResizedBitmap();
		resizedBitmap.setHopefulReiszedBitmapWidth(resizedBitmapWidth);
		resizedBitmap.setHopefulResizedBitmapHeight(resizedBitmapHeight);

		// bitmap은 화면크기에 딱 맞게 줄일수가 없다.. 1/2, 1/3, 1/4 .. 1/n 과 같이 줄일 수 있음.
		resizedBitmap.setBitmap(loadImageWithSampling(realImagePath, resizedBitmapWidth, resizedBitmapHeight, Bitmap.Config.ARGB_8888));

		return resizedBitmap;
	}

	public static synchronized int[] displayImageWithMaxSizeSampling(ImageView imageView, Uri imageUri, int maxWidth, int maxHeight) {
		ResizedBitmap resizedBitmap = getImageWithMaxSizeSampling(imageUri, maxWidth, maxHeight);

		imageView.setImageBitmap(resizedBitmap.getBitmap());

		// layout 수정
		/*ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
		layoutParams.width = resizedBitmap.getHopefulReiszedBitmapWidth();
		layoutParams.height = resizedBitmap.getHopefulResizedBitmapHeight();*/

		return new int[] {resizedBitmap.getHopefulReiszedBitmapWidth(), resizedBitmap.getHopefulResizedBitmapHeight()};
	}

	public static int[] getBitmapSize(String imagePath) {
		Options savedBitmapSize = ImageUtil.getBitmapOptions(imagePath);

		int savedImageWidth = savedBitmapSize.outWidth;
		int savedImageHeight = savedBitmapSize.outHeight;

		try {
			ExifInterface exif = new ExifInterface(imagePath);
			int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

			if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90 || exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
				int temp = savedImageWidth;
				savedImageWidth = savedImageHeight;
				savedImageHeight = temp;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return new int[] {savedImageWidth, savedImageHeight};
	}

	/**
	 * 해상도별 썸네일 가로 사이즈 구함
	 *  
	 * @param activity
	 * @return
	 */
	public static int dynamicThumbnailWidth(Context context) {

		WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
		Display display = windowManager.getDefaultDisplay();
		DisplayMetrics metrics = new DisplayMetrics();
		display.getMetrics(metrics);
		int deviceWidth = metrics.widthPixels;

		/*
		 *  240, 320 해상도 제품도 존재함
		 *  해당 제품의 경우, 적절한 값을 넣어 줄것, 테스트 필요 
		 */
		int width = 0;
		if (deviceWidth == 240) {
			width = 150;
		} else if (deviceWidth == 320) {
			width = 230;
		} else {
			width = 390;
		}

		return width;
	}

	/**
	 * 썸네일 가로길이를 바탕으로 높이를 구함
	 * 
	 * @param thumnailWidth
	 * @param realWidth
	 * @param realHeight
	 * @return 썸네일 높이
	 */
	public static int getThumnailHeight(int thumnailWidth, int realWidth, int realHeight) {
		try {
			int result1 = thumnailWidth * realHeight;
			int thumnailHeight = result1 / realWidth;
			return thumnailHeight;
		} catch (Exception e) {
			return 0;
		}
	}

	public static boolean isImageExisted(String path) {
		return (new File(path)).exists();
	}

	public static Bitmap getBitmapFromUrl(String urlStr, BitmapFactory.Options options) {
		Bitmap bitmap = null;
		try {
			URL url = new URL(urlStr);
			HttpURLConnection connection = (HttpURLConnection)url.openConnection();
			connection.setDoInput(true);
			connection.connect();
			InputStream input = connection.getInputStream();
			bitmap = BitmapFactory.decodeStream(input, null, options);
			connection.disconnect();
		} catch (IOException e) {
			return null;
		}
		return bitmap;
	}

	public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
		final int height = options.outHeight;
		final int width = options.outWidth;
		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			final int heightRatio = Math.round((float)height / (float)reqHeight);
			final int widthRatio = Math.round((float)width / (float)reqWidth);
			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
		}

		return inSampleSize;
	}

	public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeFile(path, options);
		options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
		options.inJustDecodeBounds = false;
		return BitmapFactory.decodeFile(path, options);
	}

	public static Bitmap decodeSampledBitmapFromUrl(String urlStr, int reqWidth, int reqHeight) {
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		Bitmap bitmap = null;
		try {
			URL url = new URL(urlStr);
			HttpURLConnection connection = (HttpURLConnection)url.openConnection();
			connection.setDoInput(true);
			connection.connect();
			InputStream input = connection.getInputStream();
			BitmapFactory.decodeStream(input, null, options);
			options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
			options.inJustDecodeBounds = false;
			bitmap = BitmapFactory.decodeStream(input, null, options);
			connection.disconnect();
		} catch (IOException e) {
			return null;
		}
		return bitmap;
	}

	public static void makeDrawableRepeat(Drawable object) {
		BitmapDrawable tile = (BitmapDrawable)object;
		tile.mutate();
		tile.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
	}

	/**
	 * Thumbnail은 품질이 좀 떨어져도 되므로 속도를 위해 품질을 희생한다.
	 * 
	 * @param path
	 * @param width
	 * @param height
	 * @return
	 */
	public static Bitmap decodeSampledBitmapForThumbnail(String path, int width, int height) {
		BitmapFactory.Options option = new BitmapFactory.Options();
		option.inJustDecodeBounds = true; //우선 이미지 크기만 확인한다.
		BitmapFactory.decodeFile(path, option);

		// dp에 따라서 최소 샘플링 사이즈를 결정 (2미만은 1, 2는 2, 2초과는 4)
		final float dp = WheatBeerApplication.getContext().getResources().getDimension(R.dimen.dp);
		final int minimumSampleSize = dp < 2.0 ? 1 : (dp == 2.0 ? 2 : 4);

		if (option.outHeight * option.outWidth >= width * height) {
			option.inSampleSize = Math.max(minimumSampleSize, (int)Math.pow(2, (int)Math.floor(Math.log(option.outHeight / height) / Math.log(2))));
		}
		option.inJustDecodeBounds = false; //이미지 크기 변환만 제거
		option.inPreferredConfig = Bitmap.Config.RGB_565;

		return BitmapFactory.decodeFile(path, option);
	}
}
